﻿using System;
using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Builder;
using System.CommandLine.Help;
using System.CommandLine.Invocation;
using System.CommandLine.Parsing;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace WholeSlideImageViewer
{
    internal static class Program
    {
        [DllImport("Kernel32.dll", EntryPoint = "AttachConsole")]
        public static extern bool AttachConsole(int dwProcessId);

        [DllImport("kernel32.dll", EntryPoint = "AllocConsole")]
        private static extern bool AllocConsole();

        [DllImport("kernel32.dll", EntryPoint = "FreeConsole")]
        private static extern bool FreeConsole();

        internal static void SetupCommand(Command command)
        {
            command.Description = "Whole Slide Image Viewer WPF Application";

            command.AddOption(CommandOption());

            Option CommandOption() =>
                new Option<bool>("--console", "Create a console window for logging.")
                {
                    Arity = ArgumentArity.ZeroOrOne
                };
        }

        [STAThread]
        public static void Main(string[] args)
        {
            var builder = new CommandLineBuilder();
            var console = new MessageBoxConsole();

            SetupCommand(builder.Command);
            builder.Command.Handler = CommandHandler.Create(Run);

            builder.UseVersionOption();

            builder.UseHelp();
            builder.UseHelpBuilder(context => new HelpBuilder(console, maxWidth: 256));
            builder.UseSuggestDirective();
            builder.RegisterWithDotnetSuggest();
            builder.UseParseErrorReporting();
            builder.UseExceptionHandler();

            Parser parser = builder.Build();
            ParseResult result = parser.Parse(args);
            bool consoleAllocated = result.ValueForOption<bool>("--console");

            if (consoleAllocated)
            {
                if (AttachConsole(-1))
                {
                    consoleAllocated = false;
                }
                else
                {
                    consoleAllocated = AllocConsole();
                }
            }

            try
            {
                result.InvokeAsync(console).GetAwaiter().GetResult();
            }
            finally
            {
                if (consoleAllocated)
                {
                    FreeConsole();
                }
            }

            console.TryShow();
        }

        internal static void Run()
        {
            IHostBuilder builder = Host.CreateDefaultBuilder()
               .ConfigureAppConfiguration((hostingContext, config) =>
               {
                   IHostEnvironment env = hostingContext.HostingEnvironment;

                   config.AddInMemoryCollection(new Dictionary<string, string>
                   {
                       ["Logging:LogLevel:Default"] = "Information",
                       ["Logging:LogLevel:System"] = "Warning",
                       ["Logging:LogLevel:Microsoft"] = "Warning"
                   });

                   config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                       .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

                   config.AddEnvironmentVariables();
               })
               .ConfigureLogging((hostingContext, logging) =>
               {
                   logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                   logging.AddConsole();
                   logging.AddDebug();
               })
               .UseDefaultServiceProvider((context, options) =>
               {
                   options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
               })
               .ConfigureWebHost(webBuilder =>
               {
                   if (string.IsNullOrEmpty(webBuilder.GetSetting(WebHostDefaults.ContentRootKey)))
                   {
                       webBuilder.UseContentRoot(Directory.GetCurrentDirectory());
                   }

                   webBuilder.UseKestrel((builderContext, options) =>
                   {
                       options.Configure(builderContext.Configuration.GetSection("Kestrel"));
                       options.Listen(IPAddress.IPv6Loopback, 0);
                   })
                   .ConfigureServices((hostingContext, services) =>
                   {
                       services.AddRouting();
                   })
                   .UseStartup<WebStartup>();
               })
               .ConfigureServices(services =>
               {
                   WpfStartup.ConfigureServices(services);
               });

            IHost? host = builder.Build();

            var app = new App(host);
            app.InitializeComponent();
            app.Run();
        }
    }
}
